#include<stdio.h>
#include<stdlib.h>
#include "mytbf.h"
#include<errno.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
#include<time.h>

#define min(a,b) ((a)>(b)?(b):(a))


static struct mytbf_st* job[MYTBF_MAX];
static pthread_mutex_t mut_job=PTHREAD_MUTEX_INITIALIZER;
static pthread_once_t once_control=PTHREAD_ONCE_INIT;
static pthread_t tid_alrm;


struct mytbf_st
{
	int token; //令牌数
	int cps; //流速
	int burst;//上限
	int pos;//下标
	pthread_mutex_t mut;//token互斥量
	pthread_cond_t cond;
};

static int get_free_pos_unlocked(void)
{
	int i;
	for(i=0;i<MYTBF_MAX;i++)
	{
		if(job[i]==NULL)
			return i;
	}
	return -1;
}

static void *thr_alrm(void *p)
{
	struct timespec req;
	req.tv_sec=1;
	req.tv_nsec=0;

	while(1)
	{
		pthread_mutex_lock(&mut_job);
		for(int i=0;i<MYTBF_MAX;i++)
		{
			if(job[i]!=NULL)
			{
				pthread_mutex_lock(&job[i]->mut);
				job[i]->token+=job[i]->cps;
				if(job[i]->token>job[i]->burst)
					job[i]->token=job[i]->burst;
				pthread_cond_broadcast(&job[i]->cond);
				pthread_mutex_unlock(&job[i]->mut);
			}
		}
		pthread_mutex_unlock(&mut_job);
		nanosleep(&req,0);
	}

}
//有可能出错了，需要恢复
static void module_unload(void)
{
	int i;
	//将运行的线程回收
	pthread_cancel(tid_alrm);
	pthread_join(tid_alrm,NULL);
	for(i=0;i<MYTBF_MAX;i++)
	{
		if(job[i]!=NULL)
		{
			mytbf_destory(&job[i]);
		}
	}

	pthread_mutex_destroy(&mut_job);
}

//发出第一个信号
static void module_load(void)
{
	int err;
	err=pthread_create(&tid_alrm,NULL,thr_alrm,NULL);
	if(err)
	{
		fprintf(stderr,"pthread_create:%s\n",strerror(err));	
		exit(1);
	}
	
	//钩子函数
	atexit(module_unload);
}

mytbf_st *mytbf_init(int cps,int burst)
{
	struct mytbf_st *me;
	int pos;
	
	pthread_once(&once_control,module_load);
		
	me=malloc(sizeof(*me));
	if(me==NULL)
	{
		return NULL; 
	}
	me->token=0;
	me->cps=cps;
	me->burst=burst;
	pthread_cond_init(&me->cond,NULL);
	pthread_mutex_init(&me->mut,NULL);
	pthread_mutex_lock(&mut_job);
	
	pos=get_free_pos_unlocked();
	if(pos<0)
	{
		pthread_mutex_unlock(&mut_job);
		free(me);
		return NULL;
	}
	me->pos=pos;
	job[pos]=me;
	
	pthread_mutex_unlock(&mut_job);
	
	return me;
}

int mytbf_fetchtoken(mytbf_st *ptr, int size)
{
	int n;
	struct mytbf_st *me=ptr;

	if(size<=0)
		return -EINVAL;
	
	pthread_mutex_lock(&me->mut);
	while(me->token<=0)
	{
		pthread_cond_wait(&me->cond,&me->mut);
	}
	n=min(size,me->token);
	me->token-=n;
	pthread_mutex_unlock(&me->mut);

	return n;
}

int mytbf_returntoken(mytbf_st *ptr,int size)
{
	struct	mytbf_st *me=ptr;
	if(size<=0)
		return -EINVAL;

	pthread_mutex_lock(&me->mut);
	me->token+=size;
	if(me->token>me->burst)
		me->token=me->burst;
	pthread_cond_broadcast(&me->cond);
	pthread_mutex_unlock(&me->mut);

	return size;
}
//销毁一个令牌桶
int mytbf_destory(mytbf_st *ptr)
{
	//类型转换，传过来的是Void*
	struct mytbf_st * me=ptr;
	
	pthread_mutex_lock(&mut_job);
	job[me->pos]=NULL;
	pthread_mutex_unlock(&mut_job);
	pthread_mutex_destroy(&me->mut);
	pthread_cond_destroy(&me->cond);
	free(ptr);

	return 0;
}

